package com.idlecode.panel.tool;

import cn.hutool.core.util.StrUtil;
import com.cronutils.descriptor.CronDescriptor;
import com.cronutils.model.CronType;
import com.cronutils.model.definition.CronDefinitionBuilder;
import com.cronutils.model.time.ExecutionTime;
import com.cronutils.parser.CronParser;
import com.idlecode.panel.tool.cron.*;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.ui.Messages;
import com.intellij.ui.components.JBScrollPane;

import javax.swing.*;
import javax.swing.event.DocumentEvent;
import javax.swing.event.DocumentListener;
import java.awt.*;
import java.time.ZonedDateTime;
import java.time.format.DateTimeFormatter;
import java.util.Locale;

/**
 * @program: IdleCode
 * @description
 * @author: rongjuwei
 * @create: 2024-11-07 09:00
 **/
public class CronPanel extends JPanel {

    private SecondPanel secondPanel;
    private JTextField secondTField;

    private MinutePanel minutePanel;
    private JTextField minuteTField;

    private HourPanel hourPanel;
    private JTextField hourTField;

    private DayPanel dayPanel;
    private JTextField dayTField;

    private MonthPanel monthPanel;
    private JTextField monthTField;

    private WeekPanel weekPanel;
    private JTextField weekTField;

    private YearPanel yearPanel;
    private JTextField yearTField;

    private JTextField cronTField;

    private JTextArea cronTextArea;

    //描述文本框
    private JTextField describeContentTField;

    // 定义日期时间格式
    private DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");

    public CronPanel(Project project) {
        //初始化组件
        initComponent();
        // 垂直排列
        setLayout(new BorderLayout());
        // 创建主面板，可以用来容纳多个 tab
        JTabbedPane tabbedPane = new JTabbedPane();
        // 创建“秒”操作面板
        secondPanel = new SecondPanel(secondTField);
        tabbedPane.addTab(" 秒 ", secondPanel);
        // 创建“分钟”操作面板
        minutePanel = new MinutePanel(minuteTField);
        tabbedPane.addTab(" 分钟 ", minutePanel);
        // 创建“小时”操作面板
        hourPanel = new HourPanel(hourTField);
        tabbedPane.addTab(" 小时 ", hourPanel);
        // 创建“日”操作面板
        dayPanel = new DayPanel(dayTField);
        tabbedPane.addTab(" 日 ", dayPanel);
        // 创建“月份”操作面板
        monthPanel = new MonthPanel(monthTField);
        tabbedPane.addTab(" 月份 ", monthPanel);
        // 创建“周（星期）”操作面板
        weekPanel = new WeekPanel(weekTField);
        tabbedPane.addTab(" 周（星期） ", weekPanel);
        // 创建“年份”操作面板
        yearPanel = new YearPanel(yearTField);
        tabbedPane.addTab(" 年份 ", yearPanel);
        add(tabbedPane, BorderLayout.NORTH);

        Component expressionPanel = getExpressionPanel();
        add(expressionPanel, BorderLayout.CENTER);
    }

    private void initComponent() {
        secondTField = new JTextField();
        secondTField.setEditable(false);
        secondTField.setMaximumSize(new Dimension(80, 30));
        secondTField.setPreferredSize(new Dimension(80, 30));
        secondTField.getDocument().addDocumentListener(new DocumentListener() {
            @Override
            public void insertUpdate(DocumentEvent e) {
                updateCronTFieldText();
            }

            @Override
            public void removeUpdate(DocumentEvent e) {
                updateCronTFieldText();
            }

            @Override
            public void changedUpdate(DocumentEvent e) {
                // This is called for attribute changes (like font style), but not for text changes
            }
        });

        minuteTField = new JTextField();
        minuteTField.setEditable(false);
        minuteTField.setMaximumSize(new Dimension(80, 30));
        minuteTField.setPreferredSize(new Dimension(80, 30));
        minuteTField.getDocument().addDocumentListener(new DocumentListener() {
            @Override
            public void insertUpdate(DocumentEvent e) {
                updateCronTFieldText();
            }

            @Override
            public void removeUpdate(DocumentEvent e) {
                updateCronTFieldText();
            }

            @Override
            public void changedUpdate(DocumentEvent e) {
                // This is called for attribute changes (like font style), but not for text changes
            }
        });

        hourTField = new JTextField();
        hourTField.setEditable(false);
        hourTField.setMaximumSize(new Dimension(80, 30));
        hourTField.setPreferredSize(new Dimension(80, 30));
        hourTField.getDocument().addDocumentListener(new DocumentListener() {
            @Override
            public void insertUpdate(DocumentEvent e) {
                updateCronTFieldText();
            }

            @Override
            public void removeUpdate(DocumentEvent e) {
                updateCronTFieldText();
            }

            @Override
            public void changedUpdate(DocumentEvent e) {
                // This is called for attribute changes (like font style), but not for text changes
            }
        });

        dayTField = new JTextField();
        dayTField.setEditable(false);
        dayTField.setMaximumSize(new Dimension(80, 30));
        dayTField.setPreferredSize(new Dimension(80, 30));
        dayTField.getDocument().addDocumentListener(new DocumentListener() {
            @Override
            public void insertUpdate(DocumentEvent e) {
                updateCronTFieldText();
            }

            @Override
            public void removeUpdate(DocumentEvent e) {
                updateCronTFieldText();
            }

            @Override
            public void changedUpdate(DocumentEvent e) {
                // This is called for attribute changes (like font style), but not for text changes
            }
        });

        monthTField = new JTextField();
        monthTField.setEditable(false);
        monthTField.setMaximumSize(new Dimension(20, 30));
        monthTField.getDocument().addDocumentListener(new DocumentListener() {
            @Override
            public void insertUpdate(DocumentEvent e) {
                updateCronTFieldText();
            }

            @Override
            public void removeUpdate(DocumentEvent e) {
                updateCronTFieldText();
            }

            @Override
            public void changedUpdate(DocumentEvent e) {
                // This is called for attribute changes (like font style), but not for text changes
            }
        });

        weekTField = new JTextField();
        weekTField.setEditable(false);
        weekTField.setMaximumSize(new Dimension(20, 30));
        weekTField.getDocument().addDocumentListener(new DocumentListener() {
            @Override
            public void insertUpdate(DocumentEvent e) {
                updateCronTFieldText();
            }

            @Override
            public void removeUpdate(DocumentEvent e) {
                updateCronTFieldText();
            }

            @Override
            public void changedUpdate(DocumentEvent e) {
                // This is called for attribute changes (like font style), but not for text changes
            }
        });

        yearTField = new JTextField();
        yearTField.setEditable(false);
        yearTField.setMaximumSize(new Dimension(80, 30));
        yearTField.setPreferredSize(new Dimension(80, 30));
        yearTField.getDocument().addDocumentListener(new DocumentListener() {
            @Override
            public void insertUpdate(DocumentEvent e) {
                updateCronTFieldText();
            }

            @Override
            public void removeUpdate(DocumentEvent e) {
                updateCronTFieldText();
            }

            @Override
            public void changedUpdate(DocumentEvent e) {
                // This is called for attribute changes (like font style), but not for text changes
            }
        });

        cronTField = new JTextField();
        cronTField.setMaximumSize(new Dimension(Integer.MAX_VALUE, 30));
    }

    private Component getExpressionPanel() {
        JPanel jPanel = new JPanel();
        jPanel.setLayout(new BorderLayout());
        JPanel expressionTitlePanel = createTitlePanel("表达式");
        jPanel.add(expressionTitlePanel, BorderLayout.NORTH);

        JPanel panel = new JPanel();
        panel.setLayout(new BoxLayout(panel, BoxLayout.Y_AXIS));
        //表达式字段-标题
        JPanel expressionFieldTitlePanel = new JPanel();
        expressionFieldTitlePanel.setLayout(new BoxLayout(expressionFieldTitlePanel, BoxLayout.X_AXIS));
        expressionFieldTitlePanel.add(Box.createRigidArea(new Dimension(10, 0)));
        expressionFieldTitlePanel.add(new JLabel("表达式字段: "));
        expressionFieldTitlePanel.add(Box.createHorizontalGlue()); // 右侧弹性空间
        panel.add(expressionFieldTitlePanel);
        //表达式字段-内容-第一行
        JPanel expressionFieldContentFirstRowPanel = new JPanel();
        expressionFieldContentFirstRowPanel.setLayout(new BoxLayout(expressionFieldContentFirstRowPanel, BoxLayout.X_AXIS));

        expressionFieldContentFirstRowPanel.add(Box.createRigidArea(new Dimension(5, 0)));
        expressionFieldContentFirstRowPanel.add(secondTField);
        expressionFieldContentFirstRowPanel.add(new JLabel("秒"));

        expressionFieldContentFirstRowPanel.add(Box.createRigidArea(new Dimension(10, 0)));
        expressionFieldContentFirstRowPanel.add(minuteTField);
        expressionFieldContentFirstRowPanel.add(new JLabel("分钟"));

        expressionFieldContentFirstRowPanel.add(Box.createRigidArea(new Dimension(10, 0)));
        expressionFieldContentFirstRowPanel.add(hourTField);
        expressionFieldContentFirstRowPanel.add(new JLabel("小时"));

        expressionFieldContentFirstRowPanel.add(Box.createHorizontalGlue()); // 右侧弹性空间
        panel.add(expressionFieldContentFirstRowPanel);
        //表达式字段-内容-第二行
        JPanel expressionFieldContentSecondRowPanel = new JPanel();
        expressionFieldContentSecondRowPanel.setLayout(new BoxLayout(expressionFieldContentSecondRowPanel, BoxLayout.X_AXIS));

        expressionFieldContentSecondRowPanel.add(Box.createRigidArea(new Dimension(5, 0)));
        expressionFieldContentSecondRowPanel.add(dayTField);
        expressionFieldContentSecondRowPanel.add(new JLabel("日"));

        expressionFieldContentSecondRowPanel.add(Box.createRigidArea(new Dimension(10, 0)));
        expressionFieldContentSecondRowPanel.add(monthTField);
        expressionFieldContentSecondRowPanel.add(new JLabel("月"));

        expressionFieldContentSecondRowPanel.add(Box.createRigidArea(new Dimension(10, 0)));
        expressionFieldContentSecondRowPanel.add(weekTField);
        expressionFieldContentSecondRowPanel.add(new JLabel("星期"));

        expressionFieldContentSecondRowPanel.add(Box.createRigidArea(new Dimension(10, 0)));
        expressionFieldContentSecondRowPanel.add(yearTField);
        expressionFieldContentSecondRowPanel.add(new JLabel("年"));

        expressionFieldContentSecondRowPanel.add(Box.createHorizontalGlue()); // 右侧弹性空间
        panel.add(expressionFieldContentSecondRowPanel);

        /****************添加空白行*****************/
        panel.add(Box.createRigidArea(new Dimension(Integer.MAX_VALUE, 10)));

        //Cron 表达式-标题
        JPanel cronExpressionTitlePanel = new JPanel();
        cronExpressionTitlePanel.setLayout(new BoxLayout(cronExpressionTitlePanel, BoxLayout.X_AXIS));
        cronExpressionTitlePanel.add(Box.createRigidArea(new Dimension(10, 0)));
        cronExpressionTitlePanel.add(new JLabel("Cron 表达式: "));
        cronExpressionTitlePanel.add(Box.createHorizontalGlue()); // 右侧弹性空间
        panel.add(cronExpressionTitlePanel);

        //Cron 表达式-内容
        JPanel cornExpressionContentPanel = new JPanel();
        cornExpressionContentPanel.setLayout(new BoxLayout(cornExpressionContentPanel, BoxLayout.X_AXIS));
        cornExpressionContentPanel.add(Box.createRigidArea(new Dimension(5, 0)));
        cornExpressionContentPanel.add(cronTField);
        panel.add(cornExpressionContentPanel);

        //按钮
        JPanel operatePanel = new JPanel();
        operatePanel.setLayout(new BoxLayout(operatePanel, BoxLayout.X_AXIS));
        JButton antiParsingButton = new JButton("反解析到 UI");
        operatePanel.add(antiParsingButton);
        antiParsingButton.addActionListener(e -> {
            String text = cronTField.getText();
            if (StrUtil.isBlank(text)) {
                Messages.showMessageDialog("corn表达式不能为空！", "警告", Messages.getWarningIcon());
            }
            try {
                // 创建 CronParser
                CronParser parser = new CronParser(CronDefinitionBuilder.instanceDefinitionFor(CronType.QUARTZ));

                parser.parse(text);

                String[] crons = text.split(" ");

                for (int i = 0; i < crons.length; i++) {
                    String cron = crons[i];
                    switch (i ) {
                        case 0:
                            secondPanel.inverseParseUi(cron);
                            break;
                        case 1:
                            minutePanel.inverseParseUi(cron);
                            break;
                        case 2:
                            hourPanel.inverseParseUi(cron);
                            break;
                        case 3:
                            dayPanel.inverseParseUi(cron);
                            break;
                        case 4:
                            monthPanel.inverseParseUi(cron);
                            break;
                        case 5:
                            weekPanel.inverseParseUi(cron);
                            break;
                        case 6:
                            yearPanel.inverseParseUi(cron);
                            break;
                        default:
                            break;
                    }
                }
            } catch (Exception exception) {
                Messages.showMessageDialog(exception.getMessage(), "错误", Messages.getErrorIcon());
            }
        });

        operatePanel.add(Box.createRigidArea(new Dimension(15, 0)));
        JButton runButton = new JButton("运行");
        operatePanel.add(runButton);
        runButton.addActionListener(e -> {
            cronTextArea.setText(null);
            String text = cronTField.getText();
            if (StrUtil.isNotBlank(text)) {
                try {
                    // 创建 CronParser
                    CronParser parser = new CronParser(CronDefinitionBuilder.instanceDefinitionFor(CronType.QUARTZ));
                    // 解析 cron 表达式
                    ExecutionTime executionTime = ExecutionTime.forCron(parser.parse(text));
                    // 获取当前时间
                    ZonedDateTime now = ZonedDateTime.now();
                    // 计算并打印接下来的10次执行时间
                    for (int i = 0; i < 10; i++) {
                        now = executionTime.nextExecution(now).get();
                        String format = now.format(formatter);
                        cronTextArea.append(format);
                        cronTextArea.append("\n");
                    }
                } catch (Exception exception) {
                    Messages.showMessageDialog(exception.getMessage(), "错误", Messages.getErrorIcon());
                }
            }
        });

        operatePanel.add(Box.createRigidArea(new Dimension(15, 0)));
        JButton describeButton = new JButton("描述");
        operatePanel.add(describeButton);
        describeButton.addActionListener(e -> {
            String text = cronTField.getText();
            if (StrUtil.isBlank(text)) {
                Messages.showMessageDialog("corn表达式不能为空！", "警告", Messages.getWarningIcon());
            }
            describeContentTField.setText(null);
            try {
                CronDescriptor descriptor = CronDescriptor.instance(Locale.CHINA);
                // 创建 CronParser
                CronParser parser = new CronParser(CronDefinitionBuilder.instanceDefinitionFor(CronType.QUARTZ));

                String describe = descriptor.describe(parser.parse(text));
                describeContentTField.setText(describe);
            } catch (Exception exception) {
                Messages.showMessageDialog(exception.getMessage(), "错误", Messages.getErrorIcon());
            }
        });
        panel.add(operatePanel);

        //描述-标题
        JPanel describeTitlePanel = new JPanel();
        describeTitlePanel.setLayout(new BoxLayout(describeTitlePanel, BoxLayout.X_AXIS));
        describeTitlePanel.add(Box.createRigidArea(new Dimension(10, 0)));
        describeTitlePanel.add(new JLabel("描述: "));
        describeTitlePanel.add(Box.createHorizontalGlue()); // 右侧弹性空间
        panel.add(describeTitlePanel);

        //描述-内容
        JPanel describeContentPanel = new JPanel();
        describeContentPanel.setLayout(new BoxLayout(describeContentPanel, BoxLayout.X_AXIS));
        describeContentPanel.add(Box.createRigidArea(new Dimension(5, 0)));
        describeContentTField = new JTextField();
        describeContentTField.setEditable(false);
        describeContentTField.setMaximumSize(new Dimension(Integer.MAX_VALUE, 30));
        describeContentPanel.add(describeContentTField);
        describeContentPanel.add(Box.createHorizontalGlue()); // 右侧弹性空间
        panel.add(describeContentPanel);

        //Cron 表达式-标题
        JPanel runTestPanel = new JPanel();
        runTestPanel.setLayout(new BoxLayout(runTestPanel, BoxLayout.X_AXIS));
        runTestPanel.add(Box.createRigidArea(new Dimension(10, 0)));
        runTestPanel.add(new JLabel("最近10次运行时间: "));
        runTestPanel.add(Box.createHorizontalGlue()); // 右侧弹性空间
        panel.add(runTestPanel);

        //最近10次执行结果
        JPanel runResultPanel = new JPanel();
        runResultPanel.setLayout(new BoxLayout(runResultPanel, BoxLayout.X_AXIS));
        runResultPanel.add(Box.createRigidArea(new Dimension(5, 0)));
        cronTextArea = new JTextArea();
        cronTextArea.setEditable(false);
        cronTextArea.setFont(cronTextArea.getFont().deriveFont(15f));
        JScrollPane scrollPane = new JBScrollPane(cronTextArea);
        scrollPane.setVerticalScrollBarPolicy(JScrollPane.VERTICAL_SCROLLBAR_AS_NEEDED);
        scrollPane.setHorizontalScrollBarPolicy(JScrollPane.HORIZONTAL_SCROLLBAR_AS_NEEDED);
        panel.add(scrollPane);

        jPanel.add(panel, BorderLayout.CENTER);
        return jPanel;
    }

    private JPanel createTitlePanel(String title) {
        // 创建带横线的标题
        JPanel titlePanel = new JPanel(new GridBagLayout());
        GridBagConstraints gbc = new GridBagConstraints();
        gbc.fill = GridBagConstraints.HORIZONTAL;

        // 创建标题标签
        JLabel titleLabel = new JLabel(title + " ");
        titleLabel.setFont(titleLabel.getFont().deriveFont(Font.BOLD, 12));
        titleLabel.setBorder(BorderFactory.createEmptyBorder(5, 0, 5, 0));

        // 添加标题标签
        gbc.gridx = 0;
        gbc.weightx = 0; // 不占用额外空间
        gbc.anchor = GridBagConstraints.CENTER; // 垂直居中
        titlePanel.add(titleLabel, gbc);

        // 创建分隔符
        JSeparator separator = new JSeparator();
        separator.setForeground(Color.GRAY);

        // 添加分隔符
        gbc.gridx = 1;
        gbc.weightx = 1; // 占用剩余空间
        gbc.anchor = GridBagConstraints.CENTER; // 垂直居中
        titlePanel.add(separator, gbc);
        return titlePanel;
    }

    private void updateCronTFieldText() {
        String text = secondTField.getText() + " " + minuteTField.getText() + " " + hourTField.getText() + " " +
                dayTField.getText() + " " + monthTField.getText() + " " + weekTField.getText() +
                (StrUtil.isBlank(yearTField.getText()) ? "" : (" " + yearTField.getText()));
        cronTField.setText(text);
    }

    public static void main(String[] args) {
        // 定义 cron 表达式
        String cronExpression = "0 0/15 * * * ?"; // 每15分钟执行一次
        // 创建 CronParser
        CronParser parser = new CronParser(CronDefinitionBuilder.instanceDefinitionFor(CronType.QUARTZ));
        // 解析 cron 表达式
        ExecutionTime executionTime = ExecutionTime.forCron(parser.parse(cronExpression));
        // 获取当前时间
        ZonedDateTime now = ZonedDateTime.now();
        // 计算并打印接下来的10次执行时间
        for (int i = 0; i < 10; i++) {
            now = executionTime.nextExecution(now).get();
            System.out.println(now.format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss")));
        }

    }
}
